﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
using FinPlusCommon;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusComponents
{
    public class FinPlusQuoteWrapper : FinPlusComponent
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { }; } }
        public override string[] TestStates { get { return new string[] { }; } }
        public override IFinPlusFunctions Model { get { return null; } }
        public override bool IsValid { get; set; }
        public override string ModelTest { get { return null; } }

        public IFinPlusFunction Quote { get; private set; }
        public string QuoteRef { get { return string.IsNullOrEmpty(_quoteRef) ? _quoteRef = Quote[Params.QuoteRef.ToString()].ToString() : _quoteRef; } }
        public string Instrument { get { return string.IsNullOrEmpty(_instrument) ? _instrument = Quote[Params.Instrument.ToString()].ToString() : _instrument; } }
        public string InstrumentType { get { return string.IsNullOrEmpty(_instrumentType) ? _instrumentType = Quote[Params.InstrumentType.ToString()].ToString() : _instrumentType; } }
        public string Counterparty { get { return string.IsNullOrEmpty(_counterparty) ? _counterparty = Quote[Params.Counterparty.ToString()].ToString() : _counterparty; } }
        public string BuySell { get { return string.IsNullOrEmpty(_buySell) ? _buySell = Quote[Params.BuySell.ToString()].ToString() : _buySell; } }
        public double Value { get { if (_value == null) _value = Quote.Value(Params.Quote.ToString()); return (double)_value; } }
        public double Size { get { if (_size == null) _size = Quote.Value(Params.Size.ToString()); return (double)_size; } }
        public string QuoteType { get { return string.IsNullOrEmpty(_quoteType) ? _quoteType = Quote[Params.QuoteType.ToString()].ToString() : _quoteType; } }
        public string QuoteStyle { get { return string.IsNullOrEmpty(_quoteStyle) ? _quoteStyle = Quote[Params.QuoteStyle.ToString()].ToString() : _quoteStyle; } }
        public string SourceName { get { return string.IsNullOrEmpty(_sourceName) ? _sourceName = Quote[Params.QuoteSource.ToString()].ToString() : _sourceName; } }
        public string RateType { get { return string.IsNullOrEmpty(_rateType) ? _rateType = Quote[Params.RateType.ToString()].ToString() : _rateType; } }
        public string SpreadTo { get; private set; }
        public bool IsMktToMkt { get; private set; }
        public FinPlusQuoteSpread Spread { get; set; }

        private enum Params { FunctionName, Instrument, InstrumentType, Counterparty, QuoteRef, BuySell, Quote, Size, QuoteType, QuoteStyle, QuoteSource, RateType, Rate, Price, Buy, Sell }
        private string _quoteRef, _instrument, _instrumentType, _counterparty, _buySell, _quoteType, _quoteStyle, _sourceName, _rateType;
        private object _value, _size;

        //construct
        public FinPlusQuoteWrapper(IFinPlusFunction quote, string spreadTo = "", bool isMktToMkt = false)
        {
            Quote = quote;
            SpreadTo = spreadTo;
            IsMktToMkt = isMktToMkt;
        }

        //common control interface
        public override void Dock(object component, string dock)
        {
            IsValid = false;
            throw new NotImplementedException();
        }

        public override void Initialise()
        {

        }

        public override void CommandRouter(IFinPlusFunction func) 
        { 
        
        }

        public override void Dispose() { }

        //public
        public FinPlusQuoteWrapper Clone(string newQuoteRef, string instrument, string source, string action)
        {
            try
            {
                var clone = new Function(this.Quote.ToArray());
                clone.Get(Params.QuoteRef.ToString()).Set(newQuoteRef);
                clone.Get(Params.QuoteSource.ToString()).Set(source);
                clone.Get(Params.FunctionName.ToString()).Set(clone.Name = action.ToString());
                clone.Get(Params.Instrument.ToString()).Set(instrument);
                return new FinPlusQuoteWrapper(clone);
            }
            catch (Exception e)
            {
                throw new Exception(Quote.ToString(), e);
            }
        }

        public FinPlusQuoteWrapper QuoteFromSourceSpread(string newQuoteRef, string instrument, string source, string quoteStyle, string size)
        {
            try
            {
                var clone = new Function(this.Quote.ToArray());
                var q = clone.Get(Params.Quote.ToString());
                var adjustment = this.Spread.Adjustment(this.BuySell);

                double oldQuote;
                double adj;

                if (!double.TryParse(q.Value, out oldQuote) || !double.TryParse(adjustment.ToString(), out adj)) return null;

                var rateTypeFactor = clone[Params.RateType.ToString()].ToString().Equals(Params.Rate.ToString()) ? 1 : -1;
                var buySellTypeFactor = clone[Params.BuySell.ToString()].ToString().Equals(Params.Sell.ToString()) ? -1 : 1;
                var newQuote = oldQuote + adj * rateTypeFactor * buySellTypeFactor;

                q.Set(newQuote);
                clone.Get(Params.QuoteRef.ToString()).Set(newQuoteRef);
                clone.Get(Params.Instrument.ToString()).Set(instrument);
                clone.Get(Params.QuoteStyle.ToString()).Set(quoteStyle);
                clone.Get(Params.Size.ToString()).Set(size);

                return new FinPlusQuoteWrapper(clone, this.SourceName, this.Spread.IsMktToMkt);
            }
            catch
            {
                throw;
            }
        }

        public FinPlusQuoteWrapper QuoteFromInstrumentSpread(string newQuoteRef, string instrument, string source, string spreadTo, double compositPrice, double totalAdj, string quoteStyle, string size)
        {
            try
            {
                var clone = new Function(this.Quote.ToArray());
                var q = clone.Get(Params.Quote.ToString());
                var adjustment = this.Spread.Adjustment(this.BuySell);

                var rateTypeFactor = clone[Params.RateType.ToString()].ToString().Equals(Params.Rate.ToString()) ? 1 : -1;
                var buySellTypeFactor = clone[Params.BuySell.ToString()].ToString().Equals(Params.Sell.ToString()) ? -1 : 1;
                var newQuote = compositPrice + totalAdj * rateTypeFactor * buySellTypeFactor;

                q.Set(newQuote.ToString());
                clone.Get(Params.QuoteRef.ToString()).Set(newQuoteRef);
                clone.Get(Params.Instrument.ToString()).Set(instrument);
                clone.Get(Params.QuoteStyle.ToString()).Set(quoteStyle);
                clone.Get(Params.Size.ToString()).Set(size);

                return new FinPlusQuoteWrapper(clone, spreadTo, this.Spread.IsMktToMkt);
            }
            catch
            {
                throw;
            }
        }

        public bool IsBest(FinPlusQuoteWrapper quote)
        {
            try
            {
                if (BuySell.Equals(Params.Buy.ToString())) return IsBestBuy(quote);
                if (BuySell.Equals(Params.Sell.ToString())) return IsBestSell(quote);
                throw new Exception(quote.Quote.ToString());
            }
            catch
            {
                throw new Exception(quote.Quote.ToString());
            }
        }

        public bool IsEqual(FinPlusQuoteWrapper quote)
        {
            try
            {
                if (quote == null) return false;

                if (quote.Value.Equals(Value) && quote.BuySell.Equals(BuySell)) return true;

                return false;
            }
            catch
            {
                throw new Exception(quote.Quote.ToString());
            }
        }

        //private
        private bool IsBestBuy(FinPlusQuoteWrapper quote)
        {
            try
            {
                bool isBestValue = Value > quote.Value;
                bool IsEqualAndLargerSize = Value == quote.Value && Size > quote.Size;

                if (RateType.Equals(Params.Price.ToString()) && (isBestValue || IsEqualAndLargerSize))
                    return false;
                else if (RateType.Equals(Params.Rate.ToString()) && (!isBestValue || IsEqualAndLargerSize))
                    return false;

                return true;
            }
            catch (Exception e)
            {
                throw new Exception(quote.Quote.ToString(), e);
            }
        }

        private bool IsBestSell(FinPlusQuoteWrapper quote)
        {
            try
            {

                bool isBestValue = Value > quote.Value;
                bool IsEqualAndLargerSize = Value == quote.Value && Size > quote.Size;

                if (RateType.Equals(Params.Price.ToString()) && (!isBestValue || IsEqualAndLargerSize))
                    return false;
                else if (RateType.Equals(Params.Rate.ToString()) && (isBestValue || IsEqualAndLargerSize))
                    return false;

                return true;
            }
            catch (Exception e)
            {
                throw new Exception(quote.Quote.ToString(), e);
            }
        }
    }
}
